package com.nf.teamwork.mall.config.security.api;

import com.nf.teamwork.mall.filter.JwtLoginFilter;
import com.nf.teamwork.mall.filter.JwtVerifyFilter;
import com.nf.teamwork.mall.service.UserInfService;
import com.nf.teamwork.mall.utils.RsaKeyProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * @Author: LJP
 * @Classname SecurityConfig
 * @Date: 2020-02-29 16:32
 * @Description: Spring Security安全认证框架配置类
 */
@Configuration
@EnableWebSecurity
/*开启权限控制的注解支持,一共有3种模式，如下采用的是SpringSecurity内置的注解方式来开启方法级的动态授权*/
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserInfService userInfService;
    @Autowired
    private RsaKeyProperties prop;

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userInfService).passwordEncoder(passwordEncoder());
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**")
            .cors().configurationSource(configurationSource())
            .and()
            .csrf().disable()
            /*因为是前后端分离所以用不到会话，这里将会话关闭*/
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .formLogin()
            .successHandler(new JwtLoginSuccessHandler())
            .failureHandler(new JwtAuthFailHandler())
            .and()
            .authorizeRequests()
                /*下面将注册激活控制器访问地址放行*/
            .antMatchers("/login/register", "/login/activate").permitAll()
                /*下面将Swagger用到的资源放行*/
            .antMatchers("/v2/api-docs",
                                      "/configuration/ui",
                                      "/swagger-resources",
                                      "/configuration/security",
                                      "/webjars/**",
                                      "/swagger-resources/configuration/ui",
                                      "/doc.html",
                                      "/swagger-ui.html").permitAll()
                /*下面将验证模块代码放行*/
            .antMatchers("/verify").permitAll()
            .anyRequest().authenticated()
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(new JwtAuthEntryPoint())
            .and()
            .addFilter(new JwtLoginFilter(super.authenticationManager(), prop))
            .addFilter(new JwtVerifyFilter(super.authenticationManager(), prop));
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        /*这里设置的地址将会绕过所有Spring Security过滤器*/
        web.ignoring().antMatchers("/offline");
    }

    private UrlBasedCorsConfigurationSource configurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://127.0.0.1:5500");
        config.addAllowedMethod("*");
        //设置客户端允许的头.jwt的令牌是通过header传递过来的.
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}